package cn.pconline.autoclub.task.data;

import cn.pconline.autoclub.task.DBUtils;
import cn.pconline.autoclub.task.FileUtils;
import cn.pconline.autoclub.task.util.IdGeneratorByTable;
import cn.pconline.autoclub.task.util.LogUtils;
import cn.pconline.autoclub.task.util.PcHttpUtils;
import cn.pconline.r.client.SimpleHttpTemplate;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SyncTopicReply {

    private static final Logger log = LoggerFactory.getLogger(SyncTopicReply.class);
    private static final int PAGE_SIZE = 1000;
    private static IdGeneratorByTable idGenerator = new IdGeneratorByTable();
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
    static List<String> columns = null;

    static {
        try {
            columns = DBUtils.getColumns("ac_dyna_reply");
        } catch (SQLException e) {
            log.error("get reply table columns error.", e);
        }
    }

    public static void main(String[] args) {
        LogUtils.initLog();
        if (args != null && args.length > 0 && "test".equalsIgnoreCase(args[0])) {
            log.info("test sync run ...");
            return;
        }
        /*long topicId = 4142346;
         long dynaId = 11709;
         Calendar cal = Calendar.getInstance();
         cal.set(Calendar.YEAR, 2013);
         long clubId = 1711;
         Map<String, Object> dynaInfo = new HashMap<String, Object>();
         dynaInfo.put("dyna_info_id", dynaId);
         dynaInfo.put("club_id", clubId);
         dynaInfo.put("topic_id", topicId);
         dynaInfo.put("create_date", cal.getTime());
        
         Map<String, Object> replyInfo = getTopicReplyInfo(topicId);
         Map<String, Object> forum = getForum(replyInfo);
         log.debug("forum: {}", forum);
         List<Map<String,Object>> replies = getReplies(replyInfo);
         List<Map<String, Object>> dynaReplies = topicReply2DynaReply(dynaId, replies);*/
        /*try {
         addTopicReplys(dynaInfo, getTopicReplyCount(replyInfo), dynaReplies);
         } catch (SQLException e) {
         log.error("sync dyna reply error.", e);
         }*/
        try {
            int count = 0;
            if (args != null && args.length > 0) {
                String table = args[0];
                List<String> tables = DBUtils.getTables("ac_dyna_info", 4);
                if (tables.contains(table)) {
                    log.info("start sync table: {}", table);
                    count = syncReply(table);
                } else {
                    log.info("table[{}] name is not exists", table);
                }
            } else {
                count = syncReply();
            }
            log.info("total sync {} replies.", count);
        } catch (SQLException e) {
            log.error("sync dyna reply error.", e);
        }
    }

    private static int syncReply(String table) throws SQLException {
        log.info("sync table[{}] start", table);
        int syncCount = 0;
        int pageCount = getPageCount(table);
        int page = 1;
        while (page <= pageCount) {
            log.debug("sync page info {}/{}", page, pageCount);
            List<Map<String, Object>> dynas = getDynaInfos(table, page);
            log.debug("page[{}] dynas:\n{}", page, dynas);
            for (Map<String, Object> dynaInfo : dynas) {
                long topicId = (Long) dynaInfo.get("topic_id");
                long dynaId = (Long) dynaInfo.get("dyna_info_id");
                Map<String, Object> replyInfo = getTopicReplyInfo(topicId);
                if (replyInfo == null) {
                    continue;
                }
                log.debug("topic[{}] replyInfo:\n{}", topicId, replyInfo);
                List<Map<String, Object>> replies = getReplies(replyInfo);
                List<Map<String, Object>> dynaReplies = topicReply2DynaReply(dynaId, replies);
                int replyCnt = getTopicReplyCount(replyInfo);
                addTopicReplys(dynaInfo, replyCnt, dynaReplies);
                syncCount += replyCnt;
            }
            page++;
        }
        log.info("sync table[{}] finish", table);
        return syncCount;
    }

    private static int syncReply() throws SQLException {
        List<String> tables = DBUtils.getTables("ac_dyna_info", 4);
        int syncCount = 0;
        for (String table : tables) {
            syncCount += syncReply(table);
            log.info("sync table[{}] finish", table);
        }
        return syncCount;
    }

    private static List<Map<String, Object>> topicReply2DynaReply(long dynaId, List<Map<String, Object>> replies) {
        List<Map<String, Object>> dynaReplies = new ArrayList<Map<String, Object>>();
        for (Map<String, Object> reply : replies) {
            dynaReplies.add(topicReply2DynaReply(dynaId, reply));
        }
        return dynaReplies;
    }

    private static int[] addTopicReplys(Map<String, Object> dynaInfo, int replyCnt, List<Map<String, Object>> dynaReplies) throws SQLException {
        long dynaId = (Long) dynaInfo.get("dyna_info_id");
        Date createDate = (Date) dynaInfo.get("create_date");
        long clubId = (Long) dynaInfo.get("club_id");

        StringBuilder colBuilder = new StringBuilder();
        StringBuilder paramBuilder = new StringBuilder();
        if (columns == null) {
            columns = DBUtils.getColumns("ac_dyna_reply");
        }
        for (String col : columns) {
            colBuilder.append(",").append(col);
            paramBuilder.append(",?");
        }
        String table = "ac_dyna_reply_" + (dynaId % 10);
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("insert into ").append(table).append(" (");
        sqlBuilder.append(colBuilder.substring(1));
        sqlBuilder.append(") values (");
        sqlBuilder.append(paramBuilder.substring(1));
        sqlBuilder.append(")");

        String dynaTable = "ac_dyna_info_" + sdf.format(createDate);
        String updateSql = "update " + dynaTable + " set post_count = " + replyCnt + " where dyna_info_id = " + dynaId;
        String updateIdxSql = "update ac_club_dyna_" + (clubId % 10) + " set post_count = " + replyCnt
                + " where dyna_info_id = " + dynaId + " and club_id = " + clubId;

        Connection conn = null;
        PreparedStatement ps = null;
        Statement stmt = null;
        boolean isAutoCommit = false;
        try {
            conn = DBUtils.getConnection();
            isAutoCommit = conn.getAutoCommit();
            conn.setAutoCommit(false);
            log.debug("insert sql: {}", sqlBuilder);
            ps = conn.prepareStatement(sqlBuilder.toString());
            log.debug("columns: {}", columns);
            for (Map<String, Object> reply : dynaReplies) {
                int idx = 1;
                log.debug("reply: {}", reply);
                for (String col : columns) {
                    //log.debug("{}: {}", col, reply.get(col));
                    ps.setObject(idx++, reply.get(col));
                }
                ps.addBatch();
            }
            int[] cnt = ps.executeBatch();
            log.info("add reply : {}", Arrays.toString(cnt));
            stmt = conn.createStatement();
            log.info("update dyna info reply count: {}", updateSql);
            stmt.addBatch(updateSql);
            log.info("update club dyna reply count: {}", updateIdxSql);
            stmt.addBatch(updateIdxSql);
            stmt.executeBatch();
            conn.commit();
            return cnt;
        } catch (SQLException ex) {
            conn.rollback();
            throw ex;
        } finally {
            if (conn != null) {
                conn.setAutoCommit(isAutoCommit);
            }
            DBUtils.releaseConn(conn, ps, null);
        }
    }

    @SuppressWarnings({"unchecked"})
    private static Map<String, Object> topicReply2DynaReply(long dynaId, Map<String, Object> topicReply) {
        Map<String, Object> reply = new HashMap<String, Object>();

        Map<String, Object> author = (Map<String, Object>) topicReply.get("author");

        String tableName = "ac_dyna_reply";

        reply.put("dyna_reply_id", idGenerator.generate(tableName, "dyna_reply_id"));
        reply.put("dyna_info_id", dynaId);
        reply.put("type", 1);
        reply.put("topic_id", topicReply.get("topicId"));
        reply.put("post_id", topicReply.get("postId"));
        reply.put("floor", topicReply.get("floor"));
        reply.put("create_date", topicReply.get("createAt"));
        reply.put("create_by", author.get("authorId"));
        reply.put("create_name", author.get("nickname"));

        reply.put("post_to_dyna_reply_id", 0);
        reply.put("post_to_post_id", 0);
        reply.put("post_to_user_id", 0);
        reply.put("post_to_nick_name", "");
        reply.put("post_to_floor", 0);

        reply.put("status", 1);
        String content = (String) topicReply.get("message");
        reply.put("content", content);
        if (content != null && content.indexOf("[图]") != -1) {
            reply.put("is_pic", 1);
        } else {
            reply.put("is_pic", 0);
        }
        reply.put("censored", 1);
        reply.put("update_by", author.get("authorId"));
        reply.put("create_at", topicReply.get("createAt"));
        reply.put("update_at", topicReply.get("createAt"));
        return reply;
    }

    @SuppressWarnings({"unchecked", "unused"})
    private static Map<String, Object> getForum(Map<String, Object> replyInfo) {
        return (Map<String, Object>) replyInfo.get("forum");
    }

    @SuppressWarnings("unchecked")
    private static List<Map<String, Object>> getReplies(Map<String, Object> replyInfo) {
        List<Map<String, Object>> replies = (List<Map<String, Object>>) replyInfo.get("postList");
        if (replies != null) {
            if (replies.size() <= 10) {
                replies.remove(replies.size() - 1);
            } else {
                return replies.subList(0, 10);
            }
        }
        return replies;
    }

    private static int getTopicReplyCount(Map<String, Object> replyInfo) {
        return (Integer) replyInfo.get("replyCount");
    }

    private static Map<String, Object> getTopicReplyInfo(long topicId) {
        SimpleHttpTemplate simpleHttpTemplate = PcHttpUtils.getSimpleHttpTemplate();
        String url = FileUtils.getConfig("autobbs.root") + "/intf/common/_topicRepliesJson.jsp?filterQuote=1&applicationType=autoclub&desc=true&pageSize=11&tid=" + topicId;//4084163
        String result = simpleHttpTemplate.get(url, "http://club.pcauto.com.cn");
        log.debug("\nget replies\nurl: {}\nresult:\n{}", result);
        if (result != null) {
            ObjectMapper mapper = new ObjectMapper();
            try {
                @SuppressWarnings("unchecked")
                Map<String, Object> map = mapper.readValue(result, Map.class);
                log.debug("postList: {}", map);
                if (map.get("error") != null) {
                    log.warn("not get[{}] repley info: {}", topicId, url);
                } else {
                    return map;
                }
            } catch (JsonParseException e) {
                log.error("", e);
            } catch (JsonMappingException e) {
                log.error("", e);
            } catch (IOException e) {
                log.error("", e);
            }
        }
        return null;
    }

    private static int getPageCount(String table) throws SQLException {
        int total = getTotal(table);
        if (total <= 0) {
            return 0;
        }
        return (total - 1) / PAGE_SIZE + 1;
    }

    private static List<Map<String, Object>> getDynaInfos(String table, int pageNo) throws SQLException {
        String sql = "select dyna_info_id, topic_id, club_id, create_date from " + table
                + " where type = 1 and topic_id > 0 and dyna_info_id < 48117"
                + " limit " + (pageNo - 1) * PAGE_SIZE + "," + PAGE_SIZE;
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        List<Map<String, Object>> dynas = new ArrayList<Map<String, Object>>();
        try {
            conn = DBUtils.getConnection();
            ps = conn.prepareStatement(sql);
            resultSet = ps.executeQuery();
            if (resultSet != null) {
                while (resultSet.next()) {
                    Map<String, Object> row = new HashMap<String, Object>();
                    row.put("dyna_info_id", resultSet.getLong("dyna_info_id"));
                    row.put("club_id", resultSet.getLong("club_id"));
                    row.put("topic_id", resultSet.getLong("topic_id"));
                    row.put("create_date", resultSet.getDate("create_date"));
                    dynas.add(row);
                }
            }
        } catch (SQLException ex) {
            throw ex;
        } finally {
            DBUtils.releaseConn(conn, ps, resultSet);
        }
        return dynas;
    }

    private static int getTotal(String table) throws SQLException {
        String sql = "select count(1) from " + table + " where type = 1 and topic_id > 0 and dyna_info_id < 48117";
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        log.debug("table total sql: {}", sql);
        try {
            conn = DBUtils.getConnection();
            ps = conn.prepareStatement(sql);
            resultSet = ps.executeQuery();
            if (resultSet != null && resultSet.next()) {
                return resultSet.getInt(1);
            }
        } catch (SQLException ex) {
            throw ex;
        } finally {
            DBUtils.releaseConn(conn, ps, resultSet);
        }
        return 0;
    }
}
